﻿using System.Collections.Generic;
using System.Linq;
using CardPlay.Model.ActionModel;
using CardPlay.Model.CardModel;
using CardPlay.Model.GameModel;
using CardPlay.Model.GameModel.Actions;
using CardPlay.Model.Primitives;

namespace CardPlay.DemoPack.Games.PairingVariants
{
    [Game("8B29C465-7888-42C4-B0E5-3D2D2273627F", LevelOfDifficulty.Easy, LevelOfSkill.MostlyChance, DurationOfPlay.LessThan5Minutes, Family = FamilyName)]
    public class MonteCarlo : SpatialPairingStyleGame
    {
        public MonteCarlo()
        {
            MaximumDeals = null;
            TableauColumns = 5;
            TableauRows = 5;
        }

        protected override bool IsOver
        {
            get
            {
                var tableauPiles = PilesNamed(AnyTableau);
                var totalNonEmptyPiles = tableauPiles.Count(pile => !pile.IsEmpty);
                var totalNonEmptyPilesInSuccession = tableauPiles.TakeWhile(pile => !pile.IsEmpty).Count();

                return 
                    (totalNonEmptyPiles == totalNonEmptyPilesInSuccession) &&
                    (totalNonEmptyPiles == TotalTableaus || this[Stock].IsEmpty) &&
                    !DiscardablePairs.Any();
            }
        }

        protected override void PrepareDealScript(DealScript script)
        {
            script.DealToEach(NamesOfTableaus, "up");
            script.DealRemainingFaceDownTo(Stock);
        }

        protected override IEnumerable<PartLocation[]> DiscardablePairs
        {
            get
            {
                var deltas = new[] {new Point(-1, 0), new Point(-1, -1), new Point(-1, 1), new Point(0, -1) };

                for (var row = 0; row < TableauRows; ++row)
                {
                    for (var col = 0; col < TableauColumns; ++col)
                    {
                        var pile = PileAt(new PartLocation(TableauNameAt(col, row)));
                        if (pile.IsEmpty) continue;

                        foreach (var delta in deltas)
                        {
                            var neighbouringLocation = new Point(col + delta.X, row + delta.Y);
                            if (neighbouringLocation.X < 0 || neighbouringLocation.Y < 0 || neighbouringLocation.Y >= TableauRows) continue;

                            var neighbouringPile = PileAt(new PartLocation(TableauNameAt(neighbouringLocation.X, neighbouringLocation.Y)));
                            if (!neighbouringPile.IsEmpty && neighbouringPile.TopCard.Rank == pile.TopCard.Rank)
                                yield return new[] {neighbouringPile.Top, pile.Top};
                        }
                    }
                }
            }
        }

        protected override IAction CreateDealAction()
        {
            var tableauPiles = this.NonEmptyPilesNamed(AnyTableau).Reverse().ToArray();
            if (tableauPiles.Length == TotalTableaus) return null;

            var action = new ComplexAction();
            var target = this[Stock].Top;

            foreach (var pile in tableauPiles)
            {
                ++target.Index;

                action.Add(new MoveCardAction(this, pile.Top, target));
                action.Add(new FlipCardAction(this, target));
            }

            action.Add(new DealOutTableauAction(this, target));

            return action;
        }
    }
}